package com.sky.service.common.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.BaseServiceConstant;
import com.sky.constant.MessageConstant;
import com.sky.constant.RedisConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.exception.ParameterInvalidException;
import com.sky.exception.ParameterIsNullException;
import com.sky.mapper.admin.DishFlavorMapper;
import com.sky.mapper.admin.DishMapper;
import com.sky.mapper.admin.SetmealDishMapper;
import com.sky.pojo.Dish;
import com.sky.pojo.DishFlavor;
import com.sky.result.PageResult;
import com.sky.service.common.DishService;
import com.sky.vo.DishVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 菜品业务实现
 * @author zgp
 * @version V1.0
 * @date 2025-01-14 16:10
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class DishServiceImpl implements DishService {

    private final DishFlavorMapper dishFlavorMapper;
    private final DishMapper dishMapper;
    private final SetmealDishMapper setmealDishMapper;
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void addDish(DishDTO dishDTO) {
        // 参数校验
        if( StringUtils.isEmpty(dishDTO.getName())
                || Objects.isNull(dishDTO.getCategoryId())
                || Objects.isNull(dishDTO.getPrice())
                || Objects.isNull(dishDTO.getMakeTime())
                || StringUtils.isEmpty(dishDTO.getImage() )){
            throw new ParameterInvalidException(MessageConstant.PARAMES_IS_INVALID);
        }
        // 菜品名称唯一校验
        if(Objects.nonNull(dishMapper.selectByName(dishDTO.getName()))){
            throw new ParameterInvalidException(MessageConstant.DISH_NAME_IS_EXIST);
        }
        // 业务处理
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO, dish);
        // 新增菜品
        dishMapper.insert(dish);

        List<DishFlavor> flavors = dishDTO.getFlavors();
        if(CollUtil.isNotEmpty(flavors)){
            // 设置口味对应的菜品id
            flavors.forEach(o -> o.setDishId(dish.getId()));
            dishFlavorMapper.insertOfBatch(flavors);
        }
    }

    @Override
    public PageResult<DishVO> getPageList(DishPageQueryDTO dto) {
        Integer status = dto.getStatus();
        int page = dto.getPage();
        int pageSize = dto.getPageSize();
        // 参数校验
        if(Objects.nonNull(status)
                && !StatusConstant.ENABLE.equals(status)
                && !StatusConstant.DISABLE.equals(status)){
            throw new ParameterInvalidException(MessageConstant.DISH_STATUS_IS_INVALID);
        }
        if (pageSize < BaseServiceConstant.ZERO || page < BaseServiceConstant.ZERO) {
            throw new ParameterInvalidException(MessageConstant.PAGE_PARAMETER_IS_INVALID);
        }
        Dish dish = new Dish();
        BeanUtils.copyProperties(dto, dish);

        // 分页查询
        PageHelper.startPage(page, pageSize);
        Page<DishVO> dishPage = dishMapper.selectPageList(dish);
        return new PageResult<>(dishPage.getTotal(), dishPage.getResult());
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void deleteByIds(List<Integer> ids) {
        // 校验参数
        if(CollUtil.isEmpty(ids)){
            throw new ParameterIsNullException(MessageConstant.ID_IS_NULL);
        }
        // 校验菜品是否启售，启售中不允许删除
        int count = dishMapper.countByStatusAndIds(ids, StatusConstant.ENABLE);
        if(count > 0){
            throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
        }
        // 校验菜品是否被套餐关联，被关联则不允许删除
        count = setmealDishMapper.selectByDishIds(ids);
        if(count > 0){
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }
        // 删除菜品
        dishMapper.deleteByIds(ids);
        // 删除菜品对应口味
        dishFlavorMapper.deleteByDishIds(ids);
    }

    @Override
    public void enableOrDisableDishStatus(Integer status, Long id) {
        // 参数校验
        if( (Objects.isNull(id) || Objects.isNull(status))
                && !StatusConstant.ENABLE.equals(status)
                && !StatusConstant.DISABLE.equals(status) ){
            throw new ParameterInvalidException(MessageConstant.PARAMES_IS_INVALID);
        }
        // 封装数据
        Dish dish = new Dish();
        dish.setId(id);
        dish.setStatus(status);
        dishMapper.updateById(dish);

        // 清除Redis缓存的菜品数据
        DishVO dishInfo = null;
        try {
            dishInfo = dishMapper.selectById(id);
            redisTemplate.delete(RedisConstant.INDEX_DISH_CACHE_PREFIX + dishInfo.getCategoryId());
        } catch (Exception e) {
            log.error("Redis菜品缓存清除失败，key={}", RedisConstant.INDEX_DISH_CACHE_PREFIX + dishInfo.getCategoryId(), e);
        }
    }

    @Override
    public DishVO getDishById(Long id) {
        if(Objects.isNull(id)){
            throw new ParameterIsNullException(MessageConstant.ID_IS_NULL);
        }
        return dishMapper.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void updateDish(DishDTO dishDTO) {
        // 参数校验
        if( StringUtils.isEmpty(dishDTO.getName())
                || Objects.isNull(dishDTO.getCategoryId())
                || Objects.isNull(dishDTO.getPrice())
                || Objects.isNull(dishDTO.getMakeTime())
                || StringUtils.isEmpty(dishDTO.getImage() )){
            throw new ParameterInvalidException(MessageConstant.PARAMES_IS_INVALID);
        }
        // 查询当前菜品信息
        Dish existDish = dishMapper.selectById(dishDTO.getId());
        if (Objects.isNull(existDish)) {
            throw new ParameterInvalidException(MessageConstant.DISH_NOT_EXIST);
        }

        // 菜品名称唯一校验
        if (!existDish.getName().equals(dishDTO.getName())) {
            // 如果名称被修改，检查新名称是否已被其他菜品使用
            Dish dishWithSameName = dishMapper.selectByName(dishDTO.getName());
            if (Objects.nonNull(dishWithSameName) && !dishWithSameName.getId().equals(dishDTO.getId())) {
                throw new ParameterInvalidException(MessageConstant.DISH_NAME_IS_EXIST);
            }
        }

        // 处理封装
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO, dish);
        // 修改数据
        // 1. 修改菜品数据
        dishMapper.updateById(dish);
        // 2. 删除菜品关联的口味数据
        dishFlavorMapper.deleteByDishIds(List.of(dishDTO.getId().intValue()));
        // 3. 新增修改后的口味数据
        List<DishFlavor> flavors = dishDTO.getFlavors();
        if(CollUtil.isNotEmpty(flavors)){
            flavors.forEach(o -> o.setDishId(dish.getId()));
            dishFlavorMapper.insertOfBatch(flavors);
        }
        // 清除缓存菜品数据：清除所有(修改有可能修改分类数据，会影响两个分类下的数据，因此删除全部菜品缓存)
        cleanRedisDishCache(RedisConstant.INDEX_DISH_CACHE_PREFIX + "*");
    }

    @Override
    public List<DishVO> getDishByCategoryId(Integer categoryId) {
        if(Objects.isNull(categoryId)){
            throw new ParameterIsNullException(MessageConstant.CATEGORY_ID_IS_NULL);
        }
        return dishMapper.selectByCategoryIdAndStatus(categoryId, null);
    }

    @Override
    public List<DishVO> getEnableDishByCategoryId(Integer categoryId) {
        if(Objects.isNull(categoryId)){
            throw new ParameterIsNullException(MessageConstant.CATEGORY_ID_IS_NULL);
        }
        // 查询缓存中的启用的菜品数据
        List<DishVO> dishes = null;
        try {
            dishes = (List<DishVO>)redisTemplate.opsForValue().get(RedisConstant.INDEX_DISH_CACHE_PREFIX + categoryId);
        } catch (Exception e) {
            log.error("Redis查询菜品缓存失败，key={}", RedisConstant.INDEX_DISH_CACHE_PREFIX + categoryId, e);
        }
        if(CollUtil.isEmpty(dishes)){
            // 从数据库查询，并写入Redis
            dishes = dishMapper.selectByCategoryIdAndStatus(categoryId, StatusConstant.ENABLE);
            try {
                redisTemplate.opsForValue().set(RedisConstant.INDEX_DISH_CACHE_PREFIX + categoryId, dishes, 1, TimeUnit.DAYS);
            } catch (Exception e) {
                log.error("菜品缓存写入Redis失败，key={}", RedisConstant.INDEX_DISH_CACHE_PREFIX + categoryId, e);
            }
        }
        return dishes;
    }

    /**
     * 删除匹配到的Redis缓存菜品数据
     * @param pattern key模糊匹配字符串
     */
    private void cleanRedisDishCache(String pattern){
        Set<String> keys = redisTemplate.keys(pattern);
        try {
            redisTemplate.delete(keys);
        } catch (Exception e) {
            log.info("Redis清除菜品缓存失败：key pattern = {}", pattern, e);
        }
    }
}
